package com.yjm.test.Spring5.ch3.lookupMethodInjection;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.util.StopWatch;

import com.yjm.test.Spring5.ch3.Singer;


@Configuration
@ComponentScan(basePackages="com.yjm.test.Spring5.ch3")
public class LookupMethodInjection {

	public static void displayInfo(String beanName, DemoBean bean) {
		Singer singer1 = bean.getMySinger();
		Singer singer2 = bean.getMySinger();
		System.out.println(beanName + ":Singer Instances the Same? " + (singer1 == singer2));
		
		StopWatch stopWatch = new StopWatch();
		stopWatch.start("lookupDemo");
		for (int i=0; i < 100000; i++) {
			Singer singer = bean.getMySinger();
			singer.sing();
		}
		stopWatch.stop();
		System.out.println("100000 gets took " + stopWatch.getTotalTimeMillis() + " ms");
	}
	
	public static void testXml() {
		GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
		ctx.load("classpath:spring/ch3/lookup-method-injection.xml");
		ctx.refresh();
		
		DemoBean abstractBean = ctx.getBean("abstractLookupBean", DemoBean.class);
		DemoBean standardBean = ctx.getBean("standardLookupBean", DemoBean.class);
		displayInfo("abstactLookupBean", abstractBean);
		displayInfo("standardLookupBean", standardBean);
		
		ctx.close();
	}
	
	public static void testJavaConfig() {
		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(LookupMethodInjection.class);

		DemoBean abstractBean = ctx.getBean("abstractLookupBean", DemoBean.class);
		DemoBean standardBean = ctx.getBean("standardLookupBean", DemoBean.class);
		displayInfo("abstactLookupBean", abstractBean);
		displayInfo("standardLookupBean", standardBean);
		
		ctx.close();
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		/*
		 * 查找方法注入
查找方法注入在 1.1 版本中被添加到 Spring 中，以解决当 bean 依赖于另一个具有不同生命周期的 bean 时所遇
到的问题，特别是当单例（singleton）依赖于非单例（nosingleton）时。在这种情况下 ， setter 注入和构造函数注入都会导
致单例 bean 维护一个应该是非单例 bean 的实例。在某些情况下，会希望单例 bean 在每次需要相关的 bean 时获得
一个非单例 bean 的新实例 。

查找方法注入的注意事项
当想要使用两个具有不同生命周期的 bean 时，可以使用查找方法注入。 当 bean 共享相同的生命周期时， 应该
避免使用查找方法注入，尤其是当这些 bean 都是单例时 。 运行上面示例后的输出显示了使用方法注入所获取的依赖
项的新实例与使用标准 DI 所获取的单个依赖项实例之间的性能差异。 此外，只有在必要的时候才使用查找方法注
入，即使当拥有不同生命周期的 bean 时。
假设有三个共享相同依赖项的单例 。 如果想要每个单例都有自己的依赖项实例，那么可以创建依赖项作为一个
单例，同时又希望每个单例在其生命周期中使用相同的协作者实例。在这种情况下，. setter 注入是理想的解决方案 ；
查找方法注入只会增加不必要的开销。
当使用查找方法注入时句，有几个设计准则在构建类时应该记住。在前面的示例中，都是在接口中声明了查找方
法。这样做的唯一原因是，不需要针对两种不同的 bean 类型重复 displayinfoO方法两次。 如前所述， 一般来说，不
需要使用专门用于 IoC 目的的不必要的定义来“污染”业务接口 。 另一点是 ， 虽然没必要一定让查找方法抽象化，
但这样做可以防止忘记配置查找方法，所以有时也可以使用空白的实现。当然，这只适用于 XML 配置。基于注解
的配置强制方法的空 白实现； 否则， 就不会创建 bean 。

		 */
		testXml();
		System.out.println("\n\n");
		
		testJavaConfig();
	}

}
